﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once

#include "GmStructure.h"
#include "GraphicsNodeId.h"
#include "StructureInstanceEndType.h"
#include "Coordinate3d.h"

namespace gcmp
{
    class IInstance;
    class IElement;
    class IGraphicsBRepFace;
    class IGraphicsBRepBody;
    class IPlane;
    class IDocument;

    enum class LineFamilyPositionCurveSideType;
    enum class BeamZPositioningType;
    enum class RaftFoundationZPositioningType;
    enum class StripFoundationZPositioningType;
    class UniIdentity;

    class GM_STRUCTURE_EXPORT StructureInstanceUtils
    {
#pragma region Instance Common Utility
    public:
        //设置Instance的属性面板double类型输出参数
        static bool SetInstanceOutputParamValueByParamUid(IInstance *pInstance, double value,const UniIdentity &paramDefUid);

        static double GetInstanceVolume(const IInstance *pInstance);

        static GraphicsNodeId GetInstanceSideFaceId(IInstance* pInstance);

        // 根据Y轴定位方式，调整创建构件的定位点
        static std::vector<Vector3d> GetPositioningPoints(const std::vector<Vector3d>& basePts, double thickness, LineFamilyPositionCurveSideType yPositioningType);

        // 根据偏移值，计算新位置
        // 直线：offset为正值时，直线沿起止方向向左侧偏移；
        // 圆弧：offset为正值时，圆弧沿径向扩大；
        static std::vector<Vector3d> GetPointsByOffset(const std::vector<Vector3d>& basePts, double offset);

        // 获取构件的实际长度
        static bool GetInstanceLength(const IInstance* pInstance, double& length);

        // 获取构件水平投影长度
        static bool GetInstanceHorizontalLength(const IInstance* pInstance, double& length);

        // 是否为直线构件
        static bool IsLinearInstance(const IElement* pElement, bool &bLinear);

        //获取构件 族类型 参数
        static bool GetInstanceFamilyTypeParamValueByParamUid(const IInstance *pInstance, double &value,const UniIdentity &paramDefUid);

        //获构件的定位标高
        static bool GetInstanceAssociatedLevelValue(const IInstance *pInstance, double &value);

        //获取构件 顶部标高偏移 
        static bool GetInstanceTopOffset(const IInstance *pInstance, double &topOffset);

        //获取构件 起点终点标高偏移
        static bool GetInstanceStartEndOffset(const IInstance *pInstance, double &startOffset, double &endOffset);

        // 获取构件的定位线的起止点
        static std::vector<Vector3d> GetInstanceControlPoints(const IInstance* pInstance);

#pragma endregion Instance Common Utility

#pragma region Beam Utility
    public:
        // 根据梁定位线的起止点取出梁的端面
        static std::vector<IGraphicsBRepFace*> GetBasicBeamStartEndFaces(IGraphicsBRepBody* pBody, const Vector3d& startPos, const Vector3d& endPos);

        // 根据梁定位线起止点、切面类型，求出切面
        static std::vector<OwnerPtr<IPlane>> GetBasicBeamStartEndSectionPlanes(const Vector3d& startPos, const Vector3d& endPos, InstanceEndType sectionType);

        // 得到梁的厚度
        static bool GetBeamThickness(IDocument* pDoc, const ElementId& instanceTypeId, double& thickness);
        static bool GetBeamThickness(const IInstance* pInstance, double& thickness);

        // 得到墙核心层的厚度
        static bool GetWallCoreThickness(IDocument* pDoc, const ElementId& instanceTypeId, double& thickness);

        //获取水平基本粱的顶部高程,若梁非水平，返回false且不修改value
        static bool GetBasicBeamTopElevation(const IInstance *pInstance, double &value);

        //获取水平基本梁的底部高程,若梁非水平，返回false且不修改value
        static bool GetBasicBeamBottomElevation(const IInstance *pInstance, double &value);

        //获取基本梁的起点顶部高程
        static bool GetBasicBeamStartTopElevation(const IInstance *pInstance, double &value);

        //获取基本梁的起点底部高程
        static bool GetBasicBeamStartBottomElevation(const IInstance *pInstance, double &value);

        //获取基本梁的终点顶部高程
        static bool GetBasicBeamEndTopElevation(const IInstance *pInstance, double &value);

        //获取基本梁的终点底部高程
        static bool GetBasicBeamEndBottomElevation(const IInstance *pInstance, double &value);

        //获取变截面梁顶部高程
        static bool GetVariableSectionBeamTopElevation (const IInstance *pInstance, double &value);

        //获取变截面梁起点底部高程
        static bool GetVariableSectionBeamStartBottomElevation(const IInstance *pInstance, double &value);

        //获取变截面梁终点底部高程
        static bool GetVariableSectionBeamEndBottomElevation(const IInstance *pInstance, double &value);

        //获取变截面梁底部倾斜角度
        static bool GetVariableSectionBeamBottomAngle(const IInstance *pInstance, double &value);

        //获取梁定位线位置(顶端或底端)
        static bool GetBeamZPositionLineType(const IInstance *pInstance, BeamZPositioningType &type);

        //获取基本梁截面高度
        static bool GetBasicBeamSectionHeight(const IInstance *pInstance, double &value);

        //获取变截面梁截面高度
        static bool GetVariableSectionBeamSectionHeight(const IInstance *pInstance, double &startHeight, double &endHeight);

        // 获取基本梁的倾斜角度
        static bool GetBasicBeamAngle(const IInstance* pInstance, double &angle);

        // 更新梁的定位线为三维线
        static bool UpdateBeamCoordinateSystemParameter(IInstance* pInstance);
#pragma endregion Beam Utility

#pragma region Floor Utility
    public:
        // 获取板上下两个面
        static std::vector<IGraphicsBRepFace*> GetFloorTopBottomFaces(IGraphicsBRepBody* pBody);

        //获取楼板上表面积
        static bool GetFloorTopArea(const IInstance *pInstance, double &value);

        static bool GetFloorTopElevation(const IInstance *pInstance, double &value);

        static bool GetFloorBottomElevation(const IInstance *pInstance, double &value);

        static bool GetFloorCoreThickness(const IInstance *pInstance, double &value);

        static bool GetFloorSlopeAngle(const IInstance *pInstance, double &value);

        static bool GetFloorSlopeStartEndHeight(const IInstance *pInstance, double &start,double &end);

        //获取坡度线，不存在时返回nullptr
        static const IElement* GetFloorSlopeLine(const IInstance *pInstance);
#pragma endregion Floor Utility

#pragma region Foundation Utility
    public:
        //获取筏板基础下表面面积
        static bool GetRaftFoundationBottomArea(const IInstance *pInstance, double &value);
        static bool GetRaftFoundationTopElevation(const IInstance *pInstance, double &value);
        static bool GetRaftFoundationBottomElevation(const IInstance *pInstance, double &value);
        static bool GetRaftFoundationZPositioningType(const IInstance *pInstance, RaftFoundationZPositioningType &type);
        static bool GetRaftFoundationThickness(const IInstance *pInstance, double &value);

        static bool GetStripFoundationTopElevation(const IInstance *pInstance, double &value);
        static bool GetStripFoundationBottomElevation(const IInstance *pInstance, double &value);
        static bool GetStripFoundationZPositioningType(const IInstance *pInstance, StripFoundationZPositioningType &type);
        static bool GetStripFoundationThickness(const IInstance *pInstance, double &value);
#pragma endregion Foundation Utility

#pragma region WallHole Utility
    public:
        //墙洞口有效性检测
        static bool ValidateStructureInstanceHole(const IInstance* pWall, const IInstance* pHole);
#pragma endregion WallHole Utility

    private:
        //获取直角边为|startOffset-endOffset|、|beamLenth（梁定位线投影长度）|的三角形中前者对应的夹角（ [0,90)））cos值
        static bool GetValidCosAngle(double startOffset, double endOffset, double beamLength, double &cosAngle);

    };
}
